

export const MaxInt = Math.round(Number.MAX_VALUE);
export const MaxNumber = Number.MAX_VALUE;
export const MinNumber = Number.MIN_VALUE;
// export const MaxFloat = Number.MAX_VALUE;
// export const MinFloat = Number.MIN_VALUE;


export const Pi = Math.PI;
export const TwoPi = Math.PI * 2;
export const HalfPi = Math.PI / 2;
export const QuadPi = Math.PI / 4;

export function IsNaN(val:number):boolean {
    return val === Number.NaN;
}

export function DegsToRads(degs:number):number {
    return Pi * (degs / 180);
}

//returns true if the parameter is equal to zero
export function IsZero(val:number):boolean {
    return (-MaxNumber < val) && (val < MaxNumber);
}

//returns true is the third parameter is in the range described by the
//first two
export function InRange(start:number, end:number, val:number):boolean {
    if (start < end)
    {
        if ( (val > start) && (val < end) ) return true;
        else return false;
    }
    else
    {
        if ( (val < start) && (val > end) ) return true;
        else return false;
    }
}

export function Maximum(v1:number, v2:number):number {
    return Math.max(v1, v2);
}


//----------------------------------------------------------------------------
//  some random number functions.
//----------------------------------------------------------------------------
export function RandInt(min:number, max:number): number {
    min = Math.floor(min);
    max = Math.floor(max);
    return Math.ceil(Math.random() * (max - min + 1)) - 1 + min;
}

//returns a random double between zero and 1
export function RandFloat(): number {
    return Math.random();
}

export function RandInRange(min:number, max:number): number {
    return min + Math.random() * (max - min);
}

//returns a random bool
export function RandBool():boolean {
    return Math.random() > 0.5;
}

//returns a random double between zero and 1
export function RandClamped() : number {
    return Math.random() - Math.random();
}

//returns a random number with a normal distribution. See method at
//http://www.taygeta.com/random/gaussian.html
let useLast = false;
let y2 = 0;
export function RandGaussian(mean:number = 0.0, stdandardDeviation = 1.0): number {
    let x1 = 0, x2 = 0, w = 0, y1 = 0;

    if(useLast) {
        y1 = y2;
        useLast = false;
    }
    else {
        do {
            x1 = 2.0 * Math.random() - 1.0;
            x2 = 2.0 * Math.random() - 1.0;
            w = x1 * x1 + x2 * x2;
        }
        while(w >= 1.0);

        w = Math.sqrt((-2.0 * Math.log(w)) / w);
        y1 = x1 * w;
        y2 = x2 * w;
        useLast = true;
    }
    return (mean + y1 * stdandardDeviation);
}

// RandGaussian.y2 = 0;
// RandGaussian.useLast = false;


//-----------------------------------------------------------------------
//  
//  some handy little functions
//-----------------------------------------------------------------------

export function Sigmoid(input:number, response: number = 1.0): number {
    return (1.0 / (1.0 + Math.exp(-input / response)));
}

//returns the maximum of two values
export function MaxOf(a:number, b:number) {
    return Math.max(a, b);
}

//returns the minimum of two values
export function MinOf(a:number, b:number) {
    return Math.min(a, b);
}

export function Clamp(val:number, min:number, max:number):number {
    if(min > max) {
        throw new Error("Min greatter than max");
    }

    if(val < min) return min;
    if(val > max) return max;
    return val;
}

//rounds a double up or down depending on its value
export function Rounded(val:number):number {
    return Math.round(val);
    // let integral = Math.floor(val);
    // let mantissa = val - integral;
    // if(mantissa < 0.5)  return integral;
    // else return integral + 1;
}

//rounds a double up or down depending on whether its 
//mantissa is higher or lower than offset
export function RoundUnderOffset(val:number, offset:number):number {
    let integral = Math.floor(val);
    let mantissa = val - integral;
    if(mantissa < offset)  return integral;
    else return integral + 1;
}

//compares two real numbers. Returns true if they are equal
export function isEqual(a:number, b:number) {
    if(Math.abs(a - b) < 1E-12)
        return true;
    else
        return false;
}

export function Average(ary:Array<number>):number {
    if(!ary || ary.length <= 0)
        return 0;
    let sum = 0;
    for(let num of ary) {
        sum += num;
    }
    return sum / ary.length;
}

export function StandardDeviation(ary:Array<number>):number{
    if(!ary || ary.length <= 0)
        return 0;

    let sd = 0;
    let average = Average(ary);
    for (let num of ary) {
        sd += (num - average) * (num - average);
    }
    sd /= ary.length;
    return Math.sqrt(sd);
}